/*
 *
 * Xilinx, Inc.
 * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A 
 * COURTESY TO YOU.  BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
 * ONE POSSIBLE   IMPLEMENTATION OF THIS FEATURE, APPLICATION OR 
 * STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION 
 * IS FREE FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE 
 * FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION
 * XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO 
 * THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO 
 * ANY WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE 
 * FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY 
 * AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/*
 * Xilinx EDK 10.1.03 EDK_K_SP3.6
 *
 * This file is a sample test application
 *
 * This application is intended to test and/or illustrate some 
 * functionality of your system.  The contents of this file may
 * vary depending on the IP in your system and may use existing
 * IP driver functions.  These drivers will be generated in your
 * XPS project when you run the "Generate Libraries" menu item
 * in XPS.
 *
 * Your XPS project directory is at:
 *    Y:\xilinx_projects\gamedemo\
 */


// Located in: microblaze_0/include/xparameters.h
#include "xparameters.h"

#include "stdio.h"

#include "xbasic_types.h"
#include "xgpio.h"
#include "gpio_header.h"
#include "uartlite_header.h"

/* Added for VGA peripheral */
#include "vga.h"


//====================================================

int main (void) {

   /*
    * Enable and initialize cache
    */
   #if XPAR_MICROBLAZE_0_USE_ICACHE
      microblaze_init_icache_range(0, XPAR_MICROBLAZE_0_CACHE_BYTE_SIZE);
      microblaze_enable_icache();
   #endif

   #if XPAR_MICROBLAZE_0_USE_DCACHE
      microblaze_init_dcache_range(0, XPAR_MICROBLAZE_0_DCACHE_BYTE_SIZE);
      microblaze_enable_dcache();
   #endif

   print("-- Entering main() --\r\n");

   /*
    * Peripheral SelfTest will not be run for RS232_DCE
    * because it has been selected as the STDOUT device
    */

   {
      Xuint32 status;
      
      print("\r\nRunning GpioOutputExample() for LEDs_8Bit...\r\n");

      status = GpioOutputExample(XPAR_LEDS_8BIT_DEVICE_ID,8);
      
      if (status == 0) {
         print("GpioOutputExample PASSED.\r\n");
      }
      else {
         print("GpioOutputExample FAILED.\r\n");
      }
   }


   {
      Xuint32 status;
      
      print("\r\nRunning GpioInputExample() for Buttons_4Bit...\r\n");

      Xuint32 DataRead;
      
      status = GpioInputExample(XPAR_BUTTONS_4BIT_DEVICE_ID, &DataRead);
		
		/* Print the value read from pushbuttons*/
		putnum (DataRead);
		print("\r\n");
		putnum (rand());
		print("\r\n");
      
      if (status == 0) {
         xil_printf("GpioInputExample PASSED. Read data:0x%X\r\n", DataRead);
      }
      else {
         print("GpioInputExample FAILED.\r\n");
      }
   }


   {
      XStatus status;
      
      print("\r\nRunning UartLiteSelfTestExample() for debug_module...\r\n");
      status = UartLiteSelfTestExample(XPAR_DEBUG_MODULE_DEVICE_ID);
      if (status == 0) {
         print("UartLiteSelfTestExample PASSED\r\n");
      }
      else {
         print("UartLiteSelfTestExample FAILED\r\n");
      }
   }
   /*
    * Disable cache and reinitialize it so that other
    * applications can be run with no problems
    */
   #if XPAR_MICROBLAZE_0_USE_DCACHE
      microblaze_disable_dcache();
      microblaze_init_dcache_range(0, XPAR_MICROBLAZE_0_DCACHE_BYTE_SIZE);
   #endif

   #if XPAR_MICROBLAZE_0_USE_ICACHE
      microblaze_disable_icache();
      microblaze_init_icache_range(0, XPAR_MICROBLAZE_0_CACHE_BYTE_SIZE);
   #endif

	{
	/* added for VGA */
   Xuint32 objects_array[4];
	
	/*
	* The following constant is used to wait each time around the loop. 
	* This constant might need to be tuned for faster or slower processor speeds.
	*/
	#define GAME_DELAY     10000

	/* Added for pushbutton input */
	Xuint32 DataRead;
	Xuint32 Status;
	XGpio GpioInput;
	
   volatile int Delay;

   Status = XGpio_Initialize(&GpioInput, XPAR_BUTTONS_4BIT_DEVICE_ID);
   if (Status != XST_SUCCESS)
		{
		print("PANIC! Gpio Initialize FAILED.\r\n");
		}

    /*
     * Set the direction for all signals to be inputs
     */
    XGpio_SetDataDirection(&GpioInput, 1, 0xFFFFFFFF);

	 //Initialize your input data over here: 
	 objects_array[0] = 320; // x coordinate for ball     
	 objects_array[1] = 240; // y coordinate for ball    
	 objects_array[2] = 300; // x coordinate for bar    
	 objects_array[3] = 220; // y coordinate for bar    

	 while (1) {

		//Call the FSL peripheral to display game objects
		vga(XPAR_FSL_VGA_0_INPUT_SLOT_ID, objects_array);
		
		// Get new ball position based on user input
		DataRead = XGpio_DiscreteRead(&GpioInput, 1);
		if (DataRead == 1) { // Down button
			objects_array[1] = objects_array[1]+1;
			}
		if (DataRead == 2) { // Up button
			objects_array[1] = objects_array[1]-1;
			}
		if (DataRead == 4) { // Right button
			objects_array[0] = objects_array[0]+1;
			}
		if (DataRead == 8) { // Right button
			objects_array[0] = objects_array[0]-1;
			}

		// Bar moves around randomly
		objects_array[2] = objects_array[2] - 1 + (rand() % 3);
		objects_array[3] = objects_array[3] - 1 + (rand() % 3);

		// If the ball catches up to the randomly moving bar, game is WON!
		if ((objects_array[0]==objects_array[2]) && (objects_array[1]==objects_array[3]))
			{
			print("YOU WON!\r\n");
			GpioOutputExample(XPAR_LEDS_8BIT_DEVICE_ID,8); // Go blink the LEDS!
			}
		
		/* Wrap the ball object around the screen */
		if (objects_array[0] == 0) objects_array[0] = 639-8;
		if (objects_array[1] == 0) objects_array[1] = 479-8;
		objects_array[0] = objects_array[0] % 640;
		objects_array[1] = objects_array[1] % 480;

		/* Wrap the bar object around the screen */
		if (objects_array[2] == 0) objects_array[2] = 639-8;
		if (objects_array[3] == 0) objects_array[3] = 479-8;
		objects_array[2] = objects_array[2] % 640;
		objects_array[3] = objects_array[3] % 480;

		/*
       * Wait a small amount of time or the ball will move too fast!
       */
      for (Delay = 0; Delay < GAME_DELAY; Delay++);		
	   }
	 }

   print("-- Exiting main() --\r\n");
   return 0;
}
